package com.retoc.graduationtravel.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.retoc.graduationtravel.Utils.CopyUtil;
import com.retoc.graduationtravel.Utils.SnowFlake;
import com.retoc.graduationtravel.common.ApiRestResponse;
import com.retoc.graduationtravel.common.Constant;
import com.retoc.graduationtravel.domain.User;
import com.retoc.graduationtravel.domain.req.*;
import com.retoc.graduationtravel.domain.resp.UserLoginResp;
import com.retoc.graduationtravel.domain.resp.UserResp;
import com.retoc.graduationtravel.exception.BusinessiException;
import com.retoc.graduationtravel.exception.ExceptionEnum;
import com.retoc.graduationtravel.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {

    @Autowired
    UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SnowFlake snowFlake;

    private static final Logger LOG = LoggerFactory.getLogger(UserController.class);

    @GetMapping("/all")
    public ApiRestResponse<List<UserResp>> getAll() {
        List<User> list = userService.list();
        List<UserResp> result = CopyUtil.copyList(list, UserResp.class);
        return ApiRestResponse.success(result);
    }

    @GetMapping("/one")
    public ApiRestResponse<UserResp> getOne(@RequestParam("id") Long userid) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", userid);
        User one = userService.getOne(queryWrapper);
        UserResp result = new UserResp();
        BeanUtils.copyProperties(one, result);
        return ApiRestResponse.success(result);
    }

    @GetMapping("/list")
    public ApiRestResponse<List<UserResp>> getUser(@Valid UserQueryReq req) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        //两个其中一个为空，用or
        if ((ObjectUtils.isEmpty(req.getName()) && !ObjectUtils.isEmpty(req.getUserName())) || (!ObjectUtils.isEmpty(req.getName()) && ObjectUtils.isEmpty(req.getUserName()))) {
            qw.like("user_name", req.getUserName()).or()
                    .like("name", req.getName());
        }
        //两个条件都不为空，用and
        if (!ObjectUtils.isEmpty(req.getName()) && !ObjectUtils.isEmpty(req.getUserName())) {
            qw.like("user_name", req.getUserName()).like("name", req.getName());
        }
        //两个条件都为空，则查询所有
        if (ObjectUtils.isEmpty(req.getName()) && ObjectUtils.isEmpty(req.getUserName())) {
            qw = null;
        }
        List<User> list = userService.list(qw);
        List<UserResp> result = CopyUtil.copyList(list, UserResp.class);
        return ApiRestResponse.success(result);
    }

//    //放弃该接口，把新增与修改直接分开成2个接口
//    //用户新增&更新接口，无ID为新增，有ID为更新
//    @PostMapping("/saveAndUpdate")
//    public ApiRestResponse<User> save(@Valid @RequestBody UserSaveReq req) {
//        req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));
//        User user = CopyUtil.copy(req, User.class);
//        QueryWrapper<User> qw = new QueryWrapper<>();
//        qw.eq("user_name", req.getUserName());
//        User one = userService.getOne(qw);
//        //判断传入的请求账号是否已经有ID，如果已经有ID，即为更改，如果没有ID，就是新增
//        if (req.getId() == null) {
//            //新增时以新增请求的用户名查询，如果能查出记录则表示重名，如果记录为空，则可以新增。
//            if (one == null) {
//                user.setAdmin(0);
//                user.setRegisterTime(new Date());
//                boolean result = userService.saveOrUpdate(user);
//                if (result) {
//                    user.setPassword(null);
//                    return ApiRestResponse.success(user);
//                } else {
//                    return ApiRestResponse.error(ExceptionEnum.UPDATE_FAIL);
//                }
//            } else {
//                //新增记录时用户名已经被注册，提示用户名重复
//                return ApiRestResponse.error(ExceptionEnum.REPEATNAME_FAIL);
//            }
//            //ID不为空，下面是修改操作
//        } else {
//            //修改时，如果能找到记录，则把记录修改。密码另外做接口重置，所以直接把旧值赋值
//            if (one == null) {
//                User userOld = userService.getById(req.getId());
//                user.setPassword(userOld.getPassword());
//                user.setRegisterTime(userOld.getRegisterTime());
//                user.setPhoto(userOld.getPhoto());
//                boolean result = userService.saveOrUpdate(user);
//                if (result) {
//                    user.setPassword(null);
//                    return ApiRestResponse.success(user);
//                } else {
//                    return ApiRestResponse.error(ExceptionEnum.UPDATE_FAIL);
//                }
//            } else {
//                return ApiRestResponse.error(ExceptionEnum.REPEATNAME_FAIL);
//            }
//        }
//    }

    @PostMapping("/insert")
    public ApiRestResponse<User> insert(@Valid @RequestBody UserSaveReq req) {
        //以提交的用户名查询是否已经有相同用户名，如果已有注册的用户名，返回错误信息告诉用户该用户名已经被注册
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("user_name", req.getUserName());
        User checkUser = userService.getOne(qw);
        if (checkUser != null) {
            return ApiRestResponse.error(ExceptionEnum.REPEATNAME_FAIL);
        } else {
            //如果用户名没被注册，则新建用户
            User user = CopyUtil.copy(req, User.class);
            user.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));
            user.setAdmin(0);
            user.setRegisterTime(new Date());
            boolean result = userService.save(user);
            if (result) {
                user.setPassword(null);
                return ApiRestResponse.success(user);
            } else {
                return ApiRestResponse.error(ExceptionEnum.UPDATE_FAIL);
            }
        }

    }

    //更新用户接口
    @PostMapping("/update")
    public ApiRestResponse<User> userUpdate(@Valid @RequestBody UserUpdateReq req) {
        User user = CopyUtil.copy(req, User.class);
        userService.updateById(user);
        return ApiRestResponse.success(user);
    }

    //重置密码
    @PostMapping("/reset")
    public ApiRestResponse<Long> reset(@Valid @RequestBody UserResetPasswordReq req) {
        req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));
        req.setOldPassword(DigestUtils.md5DigestAsHex(req.getOldPassword().getBytes()));
        User userCheckId = userService.getById(req.getId());
        if (userCheckId.getPassword().equals(req.getOldPassword())) {
            UpdateWrapper<User> uw = new UpdateWrapper<>();
            uw.eq("id", req.getId()).set("password", req.getPassword());
            boolean result = userService.update(null, uw);
            if (result) {
                return ApiRestResponse.success(req.getId());
            } else {
                return ApiRestResponse.error(ExceptionEnum.UPDATE_FAIL);
            }
        } else {
            return ApiRestResponse.error(ExceptionEnum.OLDPASSWORD_ERROR);
        }
    }

    @DeleteMapping("/delete")
    public ApiRestResponse<Integer> delete(@RequestParam("id") Long userid) {
        boolean result = userService.removeById(userid);
        if (result) {
            return ApiRestResponse.success();
        } else {
            return ApiRestResponse.error(ExceptionEnum.DELETE_FAIL);
        }
    }

    @PostMapping("login")
    public ApiRestResponse<UserLoginResp> login(@Valid @RequestBody UserLoginReq req) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("user_Name", req.getUserName());
        User userDB = userService.getOne(qw);
        if (ObjectUtils.isEmpty(userDB)) {
            throw new BusinessiException(ExceptionEnum.LOGIN_FAIL);
        } else {
            String reqPassword = DigestUtils.md5DigestAsHex(req.getPassword().getBytes());
            boolean result = userDB.getPassword().equals(reqPassword);
            if (result) {
                UserLoginResp resp = CopyUtil.copy(userDB, UserLoginResp.class);
                Long token = snowFlake.nextId();
                LOG.info("生成单点登陆token,并放入redis中：{}" + token.toString());
                resp.setToken(token.toString());
                redisTemplate.opsForValue().set(token.toString(), resp, 3600 * 24, TimeUnit.SECONDS);
                return ApiRestResponse.success(resp);
            } else {
                throw new BusinessiException(ExceptionEnum.LOGIN_FAIL);
            }
        }
    }

    @GetMapping("logout/{token}")
    public ApiRestResponse logout(@PathVariable("token") String token) {
        redisTemplate.delete(token);
        LOG.info("用户登出token,并在redis中删除：{}", token.toString());
        return ApiRestResponse.success();
    }

    @PostMapping("upload/file")
    public ApiRestResponse upload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
        String filename = file.getOriginalFilename();
        assert filename != null;
        String suffixName = filename.substring(filename.lastIndexOf("."));
        String newFileName = UUID.randomUUID().toString() + suffixName;
        File fileDirectory = new File(Constant.FILE_UPLOAD_DIR);
        File destFile = new File(Constant.FILE_UPLOAD_DIR + newFileName);
        if (!fileDirectory.exists()) {
            if (fileDirectory.mkdir()) {
                throw new BusinessiException(ExceptionEnum.MKDIR_FAIL);
            }
        }
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            return ApiRestResponse.success(getHost(new URI(request.getRequestURL() + "")) + "/images/" + newFileName);
        } catch (URISyntaxException e) {
            return ApiRestResponse.error(ExceptionEnum.UPLOAD_FAIL);
        }
    }

    private URI getHost(URI uri) {
        URI effectiveURI;
        try {
            effectiveURI = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null);
        } catch (URISyntaxException e) {
            effectiveURI = null;
        }
        return effectiveURI;
    }
}
